#pragma once

#include <concepts>

#include <utils/Concepts.h>
#include <utils/bit_utils/ConditionalAdd.h>
#include <utils/bit_utils/CudaWrapper.h>

namespace solar::bit
{
    // value = condition ? -value : value
    template <std::signed_integral T1> constexpr void conditionalNegate(bool condition, T1& value)
    {
        value = (value ^ -condition) + condition;
    }

    // value = condition ? -value : value
    template <std::signed_integral T1>
    constexpr auto conditionalNegate2(bool condition, T1 value) -> T1
    {
        return (value ^ -condition) + condition;
    }

    // value = condition ? -value : value
    template <std::floating_point T1>
    inline __host__ __device__ void conditionalNegate(bool condition, T1& value)
    {
        conditionalAdd(condition, value, -value * 2);
    }

    // value = condition ? -value : value
    template <std::floating_point T1>
    inline __host__ __device__ auto conditionalNegate2(bool condition, T1 value) -> T1
    {
        return conditionalAdd2(condition, value, -value * 2);
    }

    namespace const_expr
    {
        // value = condition ? -value : value
        template <std::floating_point T1>
        constexpr void conditionalNegate(bool condition, T1& value)
        {
            const_expr::conditionalAdd(condition, value, -value * 2);
        }

        // value = condition ? -value : value
        template <std::floating_point T1>
        constexpr auto conditionalNegate2(bool condition, T1 value) -> T1
        {
            return const_expr::conditionalAdd2(condition, value, -value * 2);
        }
    } // namespace const_expr

} // namespace solar::bit
